const glMatrix = require('gl-matrix');
const Bezier = require('./bezier');
const lngLat2ThetaPhiXYZ = require('./lngLat2ThetaPhiXYZ').lngLat2ThetaPhiXYZ;
const vec3 = glMatrix.vec3;
const mat3 = glMatrix.mat3;

// 由两个点的经纬度计算两点之间抛物线中的点坐标
module.exports = function getBezierPath(lnglat1, lnglat2, segment, height, radius) {
    const spaceCoor1 = lngLat2ThetaPhiXYZ(lnglat1, radius);
    const spaceCoor2 = lngLat2ThetaPhiXYZ(lnglat2, radius);

    // 两点确定向量
    const vec3AB = [(spaceCoor1.x - spaceCoor2.x), (spaceCoor1.y - spaceCoor2.y), (spaceCoor1.z - spaceCoor2.z)];
    // 两点间距一半
    const m = vec3.length(vec3AB) / 2;
    // 抛物线 y = a*x*x + c
    const c = height + (radius - Math.sqrt(radius * radius - m * m));
    const a = -1 * c / m / m;

    // 使用三次贝塞尔曲线拟合路径(起点, 最高点, 终点, 最高点t, strut length)
    const curve = Bezier.cubicFromPoints({ x: -m, y: 0 }, { x: 0, y: c }, { x: m, y: 0 }, 0.5, m / radius);
    const LUT = curve.getLUT(segment);
    const pointArr = [];
    for (let i = 0; i < LUT.length; i++) {
        pointArr.push([LUT[i].x, LUT[i].y, 0]);
    }

    const centerPoint = [(spaceCoor1.x + spaceCoor2.x) / 2, (spaceCoor1.y + spaceCoor2.y) / 2, (spaceCoor1.z + spaceCoor2.z) / 2];
    // 局部坐标系x方向基底
    const e1b = [(centerPoint[0] - spaceCoor2.x), (centerPoint[1] - spaceCoor2.y), (centerPoint[2] - spaceCoor2.z)];
    vec3.normalize(e1b, e1b);
    // 局部坐标系y方向基底
    const e2b = [(0 - centerPoint[0]), (0 - centerPoint[1]), (0 - centerPoint[2])];
    vec3.normalize(e2b, e2b);
    // 局部坐标系z方向基底
    const vec3OA = [(0 - spaceCoor1.x), (0 - spaceCoor1.y), (0 - spaceCoor1.z)];
    const vec3OB = [(0 - spaceCoor2.x), (0 - spaceCoor2.y), (0 - spaceCoor2.z)];
    const e3b = [(vec3OA[1] * vec3OB[2] - vec3OA[2] * vec3OB[1]), (vec3OA[2] * vec3OB[0] - vec3OA[0] * vec3OB[2]), (vec3OA[0] * vec3OB[1] - vec3OA[1] * vec3OB[0])]
    vec3.normalize(e3b, e3b);

    // 变换矩阵R, 算法文档: https://wenku.baidu.com/view/3facecf477232f60dccca16f.html
    const MatEa = mat3.fromValues(-1, 0, 0, 0, -1, 0, 0, 0, -1);
    const MatEb = mat3.fromValues(e1b[0], e1b[1], e1b[2], e2b[0], e2b[1], e2b[2], e3b[0], e3b[1], e3b[2]);
    const R = mat3.create();
    mat3.multiply(R, MatEa, MatEb);

    const pointWorldArr = [];
    for (let i = 0; i <= segment; i++) {
        const position = vec3.create();
        vec3.transformMat3(position, pointArr[i], R);
        vec3.add(position, position, centerPoint);
        pointWorldArr.push(position);
    }

    let k = 0;
    const out = [];
    for (let i = 0; i < pointWorldArr.length; i++) {
        for (let j = 0; j < pointWorldArr[0].length; j++) {
            out[k++] = pointWorldArr[i][j]
        }
    }

    return new Float32Array(out);
}
